package com.mas.monitor;

import jade.core.Agent;
import jade.core.behaviours.CyclicBehaviour;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;

import java.util.HashMap;
import java.util.Map;

import com.mas.common.AgentUtil;
import com.mas.common.Consts;
import com.mas.resource.ResourceAllocator;
import com.mas.session.MonitorSession;
import com.mas.session.Session;

public class MonitorResourceAgent extends Agent {

	private Map<String, ResourceAllocator> mapResourceAllocator;

	private Map<String, Session> mapSession;

	/**
	 * agent initializations: <li>Register the Resource Monitor service in the
	 * Directory Facilitator</li> <li></li>
	 */
	protected void setup() {
		System.out.println("Hello MonitorResourceAgent is ready");
		mapSession = new HashMap<String, Session>(Consts.MAX_SESSION_NO);
		initResourcesCatalog(-1.0);

		registerToDF();

		addBehaviour(new PendingForUserCFP());

		/**
		 * New Behaviour for resource monitoring
		 */
		addBehaviour(new TickerMonitorResources(this,Consts.UpdateMonitorInterval_msec));

		/**
		 * New Behaviour for resource monitoring
		 */
		addBehaviour(new TickerReleaseResources(this,Consts.ReleaseResourcesInterval_msec));

	}

	private void registerToDF() {
		DFAgentDescription dfd = new DFAgentDescription();
		dfd.setName(getAID());
		ServiceDescription sd = new ServiceDescription();
		sd.setType(Consts.AgentType_Monitor);
		sd.setName(Consts.AgentName_Monitor);
		sd.addLanguages(getAgentLanguage());
		dfd.addServices(sd);
		try {
			DFService.register(this, dfd);
		} catch (FIPAException fe) {
			fe.printStackTrace();
		}

	}

	/**
	 * Get Double defaultValue Init resourcesCatalog with all the resources with
	 * the default value
	 */
	private void initResourcesCatalog(double defaultValue) {

		mapResourceAllocator = new HashMap<String, ResourceAllocator>();

		mapResourceAllocator.put(Consts.RESOURCE_AMOUNT_TO_BUY, new ResourceAllocator(
				Consts.RESOURCE_AMOUNT_TO_BUY, defaultValue, defaultValue,
				Consts.CPU_MaxAllocationValue));

		mapResourceAllocator.put(Consts.RESOURCE_START_TIME, new ResourceAllocator(
				Consts.RESOURCE_START_TIME, defaultValue, defaultValue,
				Consts.MEM_MaxAllocationValue));

		mapResourceAllocator.put(Consts.RESOURCE_END_TIME, new ResourceAllocator(
				Consts.RESOURCE_END_TIME, defaultValue, defaultValue,
				Consts.HD_MaxAllocationValue));

		mapResourceAllocator.put(Consts.RESOURCE_NET, new ResourceAllocator(
				Consts.RESOURCE_NET, defaultValue, defaultValue,
				Consts.NET_MaxAllocationValue));
	}

	protected String getAgentLanguage() {
		return Consts.AGENT_LANG;
	}

	/**
	 * This class represents the behavior - pending for user resource for
	 * starting negotiating (CFP). expecting CFP and resource name (if the
	 * content is null assuming that all resources are needed)
	 * 
	 * @author Dudi & Efi
	 * 
	 */
	private class PendingForUserCFP extends CyclicBehaviour {
		public void action() {

			if (mapSession.size() >= Consts.MAX_SESSION_NO) {
				// cleanDeadSessions();
				System.out.println("PendingForUserCFP-> "
						+ "Cannot review more than Consts.MAX_SESSION_NO:"
						+ Consts.MAX_SESSION_NO);
				return;
			}

			MessageTemplate mt = MessageTemplate
					.MatchPerformative(ACLMessage.CFP);
			ACLMessage msg = myAgent.receive(mt);

			if (msg == null) {
				block();
			} else {
				AgentUtil.logInfo(myAgent, "Hey i got some info:"
						+ msg.getContent());
				Session session = new MonitorSession(
						(MonitorResourceAgent) myAgent, myAgent.getLocalName()
								+ "->" + msg.getSender().getLocalName());
				mapSession.put(msg.getSender().getName(), session);
				try {
					session.processIncomingCFPMsg(msg);
				} catch (FIPAException e) {
					AgentUtil.logInfo(myAgent, "Fatal Error Occur");
					e.printStackTrace(); 
					mapSession.remove(msg.getSender().getName());
				}

			}

		}

	}

	/**
	 * @return the mapResourceAllocator
	 */
	public Map getMapResourceAllocator() {
		return mapResourceAllocator;
	}
}